package cn.wolfcode.cloud.shop.service.impl;

import cn.wolfcode.cloud.shop.redis.SeckillRedisKey;
import cn.wolfcode.cloud.shop.resp.Result;
import cn.wolfcode.cloud.shop.service.ISeckillGoodService;
import cn.wolfcode.cloud.shop.domain.Goods;
import cn.wolfcode.cloud.shop.domain.SeckillGood;
import cn.wolfcode.cloud.shop.mapper.SeckillGoodMapper;
import cn.wolfcode.cloud.shop.util.JSONUtil;
import cn.wolfcode.cloud.shop.vo.SeckillGoodsVo;
import cn.wolfcode.cloud.shop.web.feign.GoodsFeignApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;


/**
 * @author Administrator
 */
@Service
public class SeckillGoodServiceImpl implements ISeckillGoodService {


    private Logger logger = LoggerFactory.getLogger("SECKILL_GOODS_SERVICE");

    @Autowired
    private SeckillGoodMapper seckillGoodMapper;

    @Autowired
    private GoodsFeignApi goodsFeignApi;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public List<SeckillGoodsVo> query() {
        //1.获取秒杀商品列表
        List<SeckillGood> seckillGoodList = seckillGoodMapper.selectAll();

        return jion(seckillGoodList);

    }

    @Override
    public SeckillGoodsVo queryById(Long id) {
        SeckillGood seckillGood = seckillGoodMapper.selectById(id);
        List<SeckillGoodsVo> seckillGoodsVos = jion(Collections.singletonList(seckillGood));
        return !CollectionUtils.isEmpty(seckillGoodsVos) ? seckillGoodsVos.get(0) : null;
    }

    @Override
    public Integer decrStockCount(Long id) {
        return seckillGoodMapper.decrStockCount(id);
    }

    @Override
    public Integer incrStockCount(Long id) {
        return seckillGoodMapper.incrStockCount(id);
    }


    private List<SeckillGoodsVo> jion(List<SeckillGood> seckillGoodList){

        //2.声明返回的秒杀商品vo集合
        List<SeckillGoodsVo> ret = new ArrayList<>(seckillGoodList.size());

        if(seckillGoodList != null && seckillGoodList.size()>0){

            //2.根据秒杀商品列表,得到一个商品id的集合
            Set<Long> idSet = new HashSet<>(seckillGoodList.size());
            for (SeckillGood seckillGood : seckillGoodList) {
                idSet.add(seckillGood.getGoodId());
            }

            //3.根据商品id列表,远程调用商品服务获取普通商品列表
            Result<List<Goods>> result = goodsFeignApi.queryByIdSet(idSet);
            //result返回值与三种情况
            //1.发生服务降级直接返回null
            //2.如果业务执行失败,进行统一的异常处理,返回结构变成Reslut<CodeMsg>
            //3.业务正常执行完毕,返回Result<List<Goods>>
            if(result == null || result.hasError()){
                logger.error("获取商品信息失败,错误信息如下:{}", JSONUtil.toJsonString(result));
                return null;
            }
            List<Goods> goodsList = result.getData();
            //4.增加一个临时缓存对象,key = 商品id, value = 商品对象good
            Map<Long, Goods> tempCache = new HashMap<>(seckillGoodList.size());
            if(goodsList != null && goodsList.size()>0){
                for (Goods good : goodsList) {
                    tempCache.put(good.getId(),good);
                }
            }

            //5.遍历秒杀商品列表,将对应得普通商品信息获取出来,组成新的vo对象
            for (SeckillGood seckillGood : seckillGoodList) {
                Goods good = tempCache.get(seckillGood.getGoodId());
                if(good!=null){
                    SeckillGoodsVo seckillGoodsVo = new SeckillGoodsVo();
                    //通过BeanUtils将属性直接复制到vo对象中
                    BeanUtils.copyProperties(good,seckillGoodsVo);
                    BeanUtils.copyProperties(seckillGood,seckillGoodsVo);
                    ret.add(seckillGoodsVo);
                }
            }
        }
        return ret;
    }


    @Override
    public List<SeckillGoodsVo> queryByCache() {
        List<Object> values = redisTemplate.opsForHash().values(SeckillRedisKey.SECKILL_GOODS_HASH.getRealKey(""));
        List<SeckillGoodsVo> vos = new ArrayList<>();
        Map<Object, Object> stockCountMap = redisTemplate.opsForHash().entries(SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(""));
        for (Object value : values) {
            String json = (String) value;
            SeckillGoodsVo seckillGoodsVo = JSONUtil.parseObject(json, SeckillGoodsVo.class);
            if(seckillGoodsVo != null){
                String stockCountStr  = (String) stockCountMap.get(seckillGoodsVo.getId() + "");
                if(!StringUtils.isEmpty(stockCountStr)){
                    int stockCount = Integer.parseInt(stockCountStr);
                    seckillGoodsVo.setStockCount(Math.max(stockCount,0));
                }
            }
            vos.add(seckillGoodsVo);
        }
        return vos;
    }

    @Override
    public SeckillGoodsVo queryByIdInCache(Long id) {
        String json = (String) redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_GOODS_HASH.getRealKey(""), id + "");
        if(json != null){
            SeckillGoodsVo seckillGoodsVo = JSONUtil.parseObject(json, SeckillGoodsVo.class);
            if(seckillGoodsVo != null){
                String stockCountStr = (String) redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(""), id + "");
                if(!StringUtils.isEmpty(stockCountStr)){
                    int stockCount = Integer.parseInt(stockCountStr);
                    seckillGoodsVo.setStockCount(stockCount);
                }
            }
            return seckillGoodsVo;
        }
        return null;
    }

}
